/**
 * @file rgb3.c
 * @author your name (you@domain.com)
 * @brief rgb24 转 YUV420P
 * @version 0.1
 * @date 2021-04-28
 * 
 * @copyright Copyright (c) 2021
 * 
 */
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>

uint8_t clip_value(uint8_t x, uint8_t min_val, uint8_t max_val);
bool rgb24ToYUV420(uint8_t *rgbBuf, int w, int h, uint8_t *yuvBuf);
int simplest_rgb24_to_yuv420(char *url_in, int w, int h, int num, char *url_out);

int main(void)
{
    simplest_rgb24_to_yuv420("lena_256x256_rgb24.rgb", 256, 256, 1, "lena_256x256_rgb24.rgb.yuv");
    printf("End\n");
    return 0;
}

int simplest_rgb24_to_yuv420(char *url_in, int w, int h, int num, char *url_out)
{
    FILE *fp = fopen(url_in, "rb+");
    if (!fp)
    {
        printf("fopen[%s]\n", strerror(errno));
        return -1;
    }

    FILE *fp1 = fopen(url_out, "wb+");
    if (!fp1)
    {
        printf("fopen[%s]\n", strerror(errno));
        return -1;
    }

    uint8_t *pic_rgb24 = (uint8_t *)malloc(w * h * 3);
    uint8_t *pic_yuv420 = (uint8_t *)malloc(w * h * 3 / 2); // 1份的y  + 1/4分的u  + 1/4 的v = 1.5 的 w * h

    for (int i = 0; i < num; i++)
    {
        fread(pic_rgb24, 1, w * h * 3, fp);
        rgb24ToYUV420(pic_rgb24, w, h, pic_yuv420);
        fwrite(pic_yuv420, 1, w * h * 3 / 2, fp1);
    }

    free(pic_rgb24);
    free(pic_yuv420);

    fclose(fp);
    fclose(fp1);

    return 0;
}

bool rgb24ToYUV420(uint8_t *rgbBuf, int w, int h, uint8_t *yuvBuf)
{
    uint8_t *ptrY, *ptrU, *ptrV, *ptrRGB;
    memset(yuvBuf, 0, w * h * 3 / 2);
    ptrY = yuvBuf;
    ptrU = yuvBuf + w * h;
    ptrV = yuvBuf + w * h + (w * h * 1 / 4);
    uint8_t y, u, v, r, g, b;
    for (int j = 0; j < h; j++)
    {
        ptrRGB = rgbBuf + w * j * 3; //一行行的偏移
        for (int i = 0; i < w; i++)
        {
            r = *(ptrRGB++);
            g = *(ptrRGB++);
            b = *(ptrRGB++);

            y = (uint8_t)((66 * r + 129 * g + 25 * b + 128) >> 8) + 16;
            u = (uint8_t)((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128;
            v = (uint8_t)((112 * r - 94 * g - 18 * b + 128) >> 8) + 128;

            *(ptrY++) = clip_value(y, 0, 255); //放置数据溢出
            if (j % 2 == 0 && i % 2 == 0)
            {
                *(ptrU++) = clip_value(u, 0, 255);
            }
            else
            {
                if (i % 2 == 0)
                {
                    *(ptrV++) = clip_value(v, 0, 255);
                }
            }
        }
    }

    return true;
}

uint8_t clip_value(uint8_t x, uint8_t min_val, uint8_t max_val)
{
    if (x > max_val)
    {
        return max_val;
    }
    else if (x < min_val)
    {
        return min_val;
    }
    else
    {
        return x;
    }
}
